/**
 * 
 */
package com.asm.examples;

import java.io.IOException;
import java.lang.reflect.Method;

import org.apache.commons.lang.StringUtils;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

/**
 * @author lionbule
 * 
 */
public class TestSimpleString extends ClassLoader implements Opcodes {

	public static void main(String[] args) throws Exception {
		String className = "ExamplePerson";
		String fieldName = "name";

		byte[] code = createClassString(className, fieldName);
		TestSimpleString loader = new TestSimpleString();
		Class<?> exampleClass = loader.defineClass(className, code, 0,
				code.length);
		
		Object invoker = exampleClass.newInstance();
		
		String setMethodName = "set" + StringUtils.capitalize(fieldName);
		String getMethodName = "get" + StringUtils.capitalize(fieldName);
		
		Method setMethod = exampleClass.getMethod(setMethodName, new Class[]{String.class});
		setMethod.invoke(invoker, new Object[]{new String("lionbule.test")}); 
		
		Method getMethod = exampleClass.getMethod(getMethodName, new Class[]{}); 
		System.out.println(getMethod.invoke(invoker, new Object[]{})); 
		
	}

	private static byte[] createClassString(String className, String fieldName) throws IOException {
		ClassWriter cw = new ClassWriter(0);

		cw.visit(V1_1, ACC_PUBLIC, className, null, "java/lang/Object", null);
		// creates a MethodWriter for the (implicit) constructor
		MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null,
				null);
		// pushes the 'this' variable
		mv.visitVarInsn(ALOAD, 0);
		// invokes the super class constructor
		mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
		mv.visitInsn(RETURN);
		// this code uses a maximum of one stack element and one local
		// variable
		mv.visitMaxs(1, 1);

		String setMethodName = "set" + StringUtils.capitalize(fieldName);
		String getMethodName = "get" + StringUtils.capitalize(fieldName);		

		
		cw.visitField(ACC_PRIVATE, fieldName, "Ljava/lang/String;", null,
					null);

		//get
		mv = cw.visitMethod(ACC_PUBLIC, getMethodName, "()Ljava/lang/String;",
					null, null);
		mv.visitCode();
		mv.visitVarInsn(ALOAD, 0);
		mv.visitFieldInsn(GETFIELD, className, fieldName,
				"Ljava/lang/String;");
		mv.visitInsn(ARETURN);
		mv.visitMaxs(1, 1);

		//set
		mv = cw.visitMethod(ACC_PUBLIC, setMethodName, "(Ljava/lang/String;)V",
				null, null);
		mv.visitCode();
		mv.visitVarInsn(ALOAD, 0);
		mv.visitVarInsn(ALOAD, 1);
		mv.visitFieldInsn(PUTFIELD, className, fieldName,
				"Ljava/lang/String;");
		mv.visitMaxs(2, 2);
		mv.visitInsn(RETURN);
		
		byte[] code = cw.toByteArray();
		
		return code;		
	}

}
